﻿using System;
using System.Threading;

/// <summary>
/// C# Time Sensitive Object
/// Auto Expiring CSharp Generic Object
/// </summary>
namespace MikeKappel.Com.CS.Model
{

    /// <summary>
    /// Time Sensitive Generic Object
    /// Structure used to associate an object to a time
    /// </summary>
    public struct TimeSensitive<T> : IDisposable
    {
        /// <summary>
        /// Timer to automatically destroy expired object
        /// </summary>
        private static Timer timer;

        /// <summary>
        /// Time related to Information
        /// </summary>
        private DateTime _time;

        /// <summary>
        /// Time Sensitive Information
        /// </summary>
        private T _value;

        /// <summary>
        /// Time Sensitive Object
        /// </summary>
        /// <param name="time">Time related to Object</param>
        /// <param name="value">Time Sensitive Object</param>
        public TimeSensitive(DateTime time, T value)
            : this(time.Subtract(DateTime.Now), value)
        {

        }

        /// <summary>
        /// Time Sensitive Object
        /// </summary>
        /// <param name="TimeDifferential">Time Differece between now and a time related to the Object</param>
        /// <param name="value">Time Sensitive Object</param>
        public TimeSensitive(TimeSpan TimeDifferential, T value)
        {
            if (TimeDifferential == null || TimeDifferential.Ticks <= 0)
                throw new NullReferenceException();

            TimerCallback timerDelegate = new TimerCallback(delegate(Object obj)
            {
                (obj as IDisposable).Dispose();
                timer.Dispose();
            });

            _time = DateTime.Now.Add(TimeDifferential);
            _value = value;

            timer = new Timer(timerDelegate, this, TimeDifferential, new TimeSpan(-1));
        }

        /// <summary>
        /// Determines if object is expired
        /// </summary>
        public Boolean IsExpired()
        {
            if (_time == default(DateTime))
            {
                return true;
            }
            else if (DateTime.Compare(DateTime.Now, _time) > 0)
            {
                this.Dispose();
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// Time related to Information
        /// </summary>
        public DateTime Time
        {
            get
            {
                return _time;
            }
            set
            {
                if (value == default(DateTime))
                    throw new NullReferenceException();
                _time = value;
            }
        }

        /// <summary>
        /// Time Sensitive Information
        /// </summary>
        public T Value
        {
            get
            {
                IsExpired();
                return _value;
            }
            set
            {
                if (IsExpired())
                    throw new ObjectDisposedException("TimeSensitive<T>");
                _value = value;
            }
        }

        /// <summary>
        /// Destroy object
        /// </summary>
        public void Dispose()
        {
            if (this.Time != default(DateTime))
            {
                _time = default(DateTime);
                _value = default(T);
            }
        }
    }
}